package cn.com.duiba.millionaire.center.biz.service.impl;

import cn.com.duiba.millionaire.center.api.cache.UserStatus;
import cn.com.duiba.millionaire.center.api.dto.ConReLiveCardSearchDto;
import cn.com.duiba.millionaire.center.api.dto.MillionaireActivityDto;
import cn.com.duiba.millionaire.center.api.dto.MillionaireQuestionDto;
import cn.com.duiba.millionaire.center.api.enums.ActivityTypeEnum;
import cn.com.duiba.millionaire.center.api.msg.SubmitAnswerMsg;
import cn.com.duiba.millionaire.center.biz.bo.ConsumeRenascenceParam;
import cn.com.duiba.millionaire.center.biz.service.*;
import cn.com.duiba.millionaire.center.biz.tool.GZIPCompressUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.javatuples.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by zzy on 2018/1/20.
 */
public abstract class AbstractAnswerHanderService {
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAnswerHanderService.class);
    @Resource(name = "redisTemplate")
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private UserStatusInfoService userStatusInfoService;
    @Autowired
    private RenascenceRecordService renascenceRecordService;
    @Autowired
    private WinnerListService winnerListService;
    @Autowired
    private MillionaireQuestionService millionaireQuestionService;
    @Autowired
    private MillionaireActivityService millionaireActivityService;
    @Autowired
    private RenascenceUsageInfoCacheService renascenceUsageInfoCacheService;
    @Autowired
    private MillionaireGameService millionaireGameService;
    /**
     * 题目答案和是否最后一题cache
     */
    private final Cache<String, Pair<String, Boolean>> questionCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(10000).build();

    /**
     * 活动配置复活卡次数配置
     */
    private final Cache<Long, Integer> activityRenascenceConfigCache = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).maximumSize(10000).build();

    public void handle(byte[] msg) {
        // 消息防重校验
        if (!uniqueCheck(msg)) {
            return;
        }
        String src = GZIPCompressUtil.ungzip(msg);
        List<SubmitAnswerMsg> msgList = JSONObject.parseArray(src, SubmitAnswerMsg.class);
        if (CollectionUtils.isEmpty(msgList)) {
            LOGGER.warn("list is empty!");
            return;
        }

        processMsgList(msgList);
    }

    private boolean uniqueCheck(byte[] msg) {
        String md5 = DigestUtils.md5Hex(msg);
        Boolean ret = redisTemplate.opsForValue().setIfAbsent(md5, "0");
        if (!ret) {
            return false;
        }
        redisTemplate.expire(md5, 2, TimeUnit.HOURS);
        return true;
    }


    abstract void processMsgList(List<SubmitAnswerMsg> msgList);


    /**
     * 回答错误处理
     *
     * @param wrongAnswerMsgList
     */
    protected void processWrongAnswer(List<SubmitAnswerMsg> wrongAnswerMsgList) {
        if(CollectionUtils.isEmpty(wrongAnswerMsgList)){
            return;
        }
        //key:活动id
        Map<Long, Set<SubmitAnswerMsg>> activityIdMappedMsg = new HashMap<>();
        //key:活动id,value:用户id集合
        Map<Long, Set<Long>> mappedCids = new HashMap<>();
        //key:用户id,value:用户选择的答案信息
        Map<Long, SubmitAnswerMsg> consumerMsgMap = new HashMap<>();
        for (SubmitAnswerMsg submitAnswerMsg : wrongAnswerMsgList) {
            Set<SubmitAnswerMsg> submitAnswerMsgListTemp = activityIdMappedMsg.get(submitAnswerMsg.getActivityId());
            if (submitAnswerMsgListTemp == null) {
                submitAnswerMsgListTemp = new HashSet<>();
                activityIdMappedMsg.put(submitAnswerMsg.getActivityId(), submitAnswerMsgListTemp);
            }
            submitAnswerMsgListTemp.add(submitAnswerMsg);

            Set<Long> ids = mappedCids.get(submitAnswerMsg.getActivityId());
            if (ids == null) {
                ids = new HashSet<>();
                mappedCids.put(submitAnswerMsg.getActivityId(), ids);
            }
            ids.add(submitAnswerMsg.getConsumerId());

            consumerMsgMap.put(submitAnswerMsg.getConsumerId(), submitAnswerMsg);
        }

        Set<Long> activityIds = activityIdMappedMsg.keySet();
        Map<Long, Integer> renascenceNumMap = findActivityRenascenceNum(activityIds);
        Map<Long, Map<Long, UserStatus>> mappedUser = userStatusInfoService.batchFind(mappedCids);
        // 复活卡消费次数超过限制，失败用户列表
        Map<Long, Set<Long>> failUserList = new HashMap<>();
        // 需要扣减复活卡复活的用户
        Map<Long, List<SubmitAnswerMsg>> needDecrUserList = new HashMap<>();
        for (SubmitAnswerMsg submitAnswerMsg : wrongAnswerMsgList) {
            Integer reliveLimit = renascenceNumMap.get(submitAnswerMsg.getActivityId());
            if (reliveLimit == null) {
                reliveLimit = 1;
                renascenceNumMap.put(submitAnswerMsg.getActivityId(),reliveLimit);
            }
            Map<Long, UserStatus> userMap = mappedUser.get(submitAnswerMsg.getActivityId());
            if (userMap == null) {
                continue;
            }
            UserStatus userStatus = userMap.get(submitAnswerMsg.getConsumerId());
            if (userStatus == null) {
                continue;
            }
            // 用户使用复活卡次数达到限制次数，不能再次使用
            if (userStatus.getRenascenceCount() >= reliveLimit) {
                Set<Long> tempIds = failUserList.get(submitAnswerMsg.getActivityId());
                if (tempIds == null) {
                    tempIds = new HashSet<>();
                    failUserList.put(submitAnswerMsg.getActivityId(), tempIds);
                }
                tempIds.add(submitAnswerMsg.getConsumerId());
            } else {
                List<SubmitAnswerMsg> tempIds = needDecrUserList.get(submitAnswerMsg.getActivityId());
                if (tempIds == null) {
                    tempIds = Lists.newArrayList();
                    needDecrUserList.put(submitAnswerMsg.getActivityId(), tempIds);
                }
                tempIds.add(submitAnswerMsg);
            }
        }

        List<SubmitAnswerMsg> allCids = Lists.newArrayList();
        for (Map.Entry<Long, List<SubmitAnswerMsg>> entry : needDecrUserList.entrySet()) {
            allCids.addAll(entry.getValue());
        }

        // 复活卡数量不够
        Set<Long> decrFailCids = new HashSet<>();
        // 复活卡数量足够
        Set<Long> normalCids = new HashSet<>();
        Map<Long, Integer> renascenceMap = renascenceRecordService.findConsumerReLiveCardByCids(allCids.stream().map(one->{
            ConReLiveCardSearchDto dto = new ConReLiveCardSearchDto();
            dto.setConsumerId(one.getConsumerId());
            dto.setActivityId(one.getActivityId());
            return dto;
        }).collect(Collectors.toList()));
        if (MapUtils.isEmpty(renascenceMap)) {
            decrFailCids.addAll(allCids.stream().map(SubmitAnswerMsg::getConsumerId).collect(Collectors.toList()));
        } else {
            for (Map.Entry<Long, Integer> entry : renascenceMap.entrySet()) {
                if (entry.getValue() == null || entry.getValue() <= 0) {
                    decrFailCids.add(entry.getKey());
                } else {
                    normalCids.add(entry.getKey());
                }
            }
        }
        Map<Long, Set<Long>> markFailMap = new HashMap<>();
        markFailMap.putAll(failUserList);
        if (!decrFailCids.isEmpty()) {
            for (Long cid : decrFailCids) {
                SubmitAnswerMsg submitAnswerMsg = consumerMsgMap.get(cid);
                Long activityId = submitAnswerMsg.getActivityId();
                Set<Long> cids = markFailMap.get(activityId);
                if (cids == null) {
                    cids = new HashSet<>();
                    markFailMap.put(activityId, cids);
                }
                cids.add(cid);
            }
        }
        //如果map里面没数据,则不需要
        if(markFailMap.size() > 0){
            userStatusInfoService.markFail(markFailMap);
        }
        if (!normalCids.isEmpty()) {
            List<SubmitAnswerMsg> normalMsgList = new ArrayList<>();
            //更新用户的复活卡使用题目
            Map<Long,Set<SubmitAnswerMsg>> successList = new HashMap<>();
            for (Long cid : normalCids) {
                SubmitAnswerMsg submitAnswerMsg = consumerMsgMap.get(cid);
                if (submitAnswerMsg != null) {
                    normalMsgList.add(submitAnswerMsg);
                }
                Set<SubmitAnswerMsg> map = successList.get(submitAnswerMsg.getActivityId());
                if(null==map){
                    map = new HashSet<>();
                    successList.put(submitAnswerMsg.getActivityId(),map);
                }
                map.add(submitAnswerMsg);
            }
            // 扣减复活卡次数
            batchConsumeRenascence(normalMsgList);
            // 记录复活卡使用
            batchAddRenascenceCount(normalMsgList);
            userStatusInfoService.consumeRenascenceCard(successList);
            addWinnerList(normalMsgList);

        }
    }

    /**
     * 批量扣减复活卡数量
     *
     * @param normalMsgList
     */
    protected void batchConsumeRenascence(List<SubmitAnswerMsg> normalMsgList) {
        Map<Long, Set<Long>> activityIdCidMap = new HashMap<>();
        Map<Long, Integer> activityIdQuestionIndexMap = new HashMap<>();
        for (SubmitAnswerMsg submitAnswerMsg : normalMsgList) {
            Set<Long> cids = activityIdCidMap.get(submitAnswerMsg.getActivityId());
            if (cids == null) {
                cids = new HashSet<>();
                activityIdCidMap.put(submitAnswerMsg.getActivityId(), cids);
            }
            cids.add(submitAnswerMsg.getConsumerId());
            activityIdQuestionIndexMap.put(submitAnswerMsg.getActivityId(), submitAnswerMsg.getQuestionIndex());
        }
        List<ConsumeRenascenceParam> consumeRenascenceParams = new ArrayList<>();
        for (Map.Entry<Long, Set<Long>> entry : activityIdCidMap.entrySet()) {
            ConsumeRenascenceParam consumeRenascenceParam = new ConsumeRenascenceParam();
            consumeRenascenceParam.setActivityId(entry.getKey());
            consumeRenascenceParam.setQuestionIndex(activityIdQuestionIndexMap.get(entry.getKey()));
            consumeRenascenceParam.setCid(entry.getValue());
            consumeRenascenceParams.add(consumeRenascenceParam);
        }
        renascenceRecordService.consumeRenascenceCard(consumeRenascenceParams);
    }

    /**
     * 查询分会场配置的复活卡使用次数
     * key: 活动id,value:复活卡使用限制个数
     * @param activityIds
     * @return
     */
    private Map<Long, Integer> findActivityRenascenceNum(Set<Long> activityIds) {
        Map<Long, Integer> activityRenascenceConfigMap = new HashMap<>();
        for (Long id : activityIds) {
            Integer count = activityRenascenceConfigCache.getIfPresent(id);
            if (count != null) {
                activityRenascenceConfigMap.put(id, count);
            }
        }
        if (activityRenascenceConfigMap.size() == activityIds.size()) {
            return activityRenascenceConfigMap;
        }
        //处理缓存中没有的活动复活卡次数信息
        activityIds.removeAll(activityRenascenceConfigMap.keySet());
        List<MillionaireActivityDto> millionaireActivityDtos = millionaireActivityService.getActivityByIds(new ArrayList<>(activityIds));
        Map<Long, MillionaireActivityDto> millionaireActivityDtoMap = millionaireActivityDtos.stream().collect(Collectors.toMap(MillionaireActivityDto::getId, m -> m));
        millionaireActivityDtoMap.entrySet().stream().forEach(entry -> {
            Long activityId = entry.getKey();
            Integer maxRenascence = entry.getValue().getMaxRevive().intValue();
            activityRenascenceConfigMap.put(entry.getKey(), maxRenascence);
            activityRenascenceConfigCache.put(activityId, maxRenascence);
        });
        return activityRenascenceConfigMap;
    }

    /**
     * 是否是最后一题
     *
     * @param activityId
     * @param questionIndex
     * @return
     */
    private boolean isLastQuestion(Long activityId, Integer questionIndex) {
        return getQuestionPair(activityId, questionIndex).getValue1();
    }

    /**
     * 获取题目答案和是否为最后一题
     *
     * @param activityId
     * @param questionIndex
     * @return
     */
    protected Pair<String, Boolean> getQuestionPair(Long activityId, Integer questionIndex) {
        String key = buildQuestionLocalCacheKey(activityId, questionIndex);
        Pair<String, Boolean> pair = questionCache.getIfPresent(key);
        if (pair != null) {
            return pair;
        }
        MillionaireQuestionDto millionaireQuestionDto = millionaireQuestionService.findQuestionByActivityIdAndIndex(activityId, questionIndex);
        if (millionaireQuestionDto == null) {
            LOGGER.warn("没有查到题目信息, activityId={}, questionIndex={}", activityId, questionIndex);
            throw new IllegalArgumentException("没有查到题目信息");
        }
        pair = Pair.with(millionaireQuestionDto.getAnswer(), millionaireQuestionDto.getLastOne());
        questionCache.put(key, pair);
        return pair;
    }

    private String buildQuestionLocalCacheKey(Long activityId, Integer questionIndex) {
        return String.valueOf(activityId) + "_" + questionIndex;
    }

    protected void addWinnerList(List<SubmitAnswerMsg> correctAnswerMsgList) {
        if(CollectionUtils.isEmpty(correctAnswerMsgList)){
            return;
        }
        //key:活动id,Pair中value0:用户id,value1:appId
        Map<Long, Set<Pair<Long, Long>>> winners = new HashMap<>();
        for (SubmitAnswerMsg msg : correctAnswerMsgList) {
            Integer actType = msg.getActType();
            boolean isLastIndex;
            if(actType != null && actType == ActivityTypeEnum.GAME.getType()){
                isLastIndex =millionaireGameService.isLastOne(msg.getActivityId(),msg.getQuestionIndex());
            }else {
                isLastIndex = isLastQuestion(msg.getActivityId(), msg.getQuestionIndex());
            }
            if (isLastIndex) {
                Set<Pair<Long, Long>> pairs = winners.get(msg.getActivityId());
                if (pairs == null) {
                    pairs = new HashSet<>();
                    winners.put(msg.getActivityId(), pairs);
                }
                pairs.add(Pair.with(msg.getConsumerId(), msg.getAppId()));
            }
        }
        if (!winners.isEmpty()) {
            winnerListService.batchAdd(winners);
        }
    }

    /**
     * 增加复活卡使用数量统计：本题有XX人使用复活卡复活
     *
     * @param normalMsgList
     */
    private void batchAddRenascenceCount(List<SubmitAnswerMsg> normalMsgList) {
        renascenceUsageInfoCacheService.batchAdd(normalMsgList);
    }
}
